#include "FrameBufferHandler.h"
#include <gl/glut.h>
#include "ObjHandler.h"
#include <malloc.h>
#include <glui.h>
#include "ShaderHandler.h"
#include "TextureHandler.h"
#include "MatixInvert.h"

#pragma comment(lib,"glui32.lib");

#define BLURSTEP	6

GLUI *glui;
GLUI_Panel *phongPanel;
GLUI_Panel *torrancePanel;
GLUI_Panel *kelemenPanel;

OBJHandler mesh;

int *displayID;

int brdfID;

int windowWidth=1024, windowHeight=768;
int diffuseWidth, diffuseHeight;

float obj_rot[16];
float lig_rot[16];

GLfloat light_position[4]={1.0, 1.0, 1.0, 0.0};

GLfloat eye_position[4]={0,0,35,1};

GLfloat light_distance=50;

int KdC[3]={8,8,8};
int KshineC=8;
float KmC=0.2;
float KfC=2.5;
int KsC=10;
float KrC=0.8;

GLfloat Kd[3]={0.8,0.8,0.8};
GLfloat Ks[3]={0.7,0.7,0.7};
GLfloat Kshine=0.8;
GLfloat Step[2];

CGcontext context;
CGprofile vProfile, fProfile;

GLuint bufferID;

int diffAlbedoID;
int specAlbedoID;
int chanelR;
int chanelB;
int chanelG;
int chanelS;

float gaussianWidth;
int gaussianIrradiance;
int gaussianStretch;

int gaussianDisplay=0;

GLfloat ProjectMatrix[16];
GLfloat MVMatrix[16];
GLfloat LightProjectMatrix[16];
GLfloat LightMVMatrix[16];
GLfloat MInvMatrix[16];
GLfloat MTranMatrix[16];

ShaderHandler vDiffuse, fDiffuse, vSpecular, fSpecular,vRender,fRender, vShadow, fShadow, vWorld2UV, fWorld2UV, vStretchUV, fStretchUV, vGaussianU, fGaussianU, vGaussianV, fGaussianV, fDistribute;
FrameBufferHandler DiffuseBuffer, SpecularBuffer, ShadowBuffer, World2UVBuffer, StretchUVBuffer, InterBuffer, GaussianBuffer[BLURSTEP], DistributeBuffer;

int *texture;

void cgErrorCallback(void)
{
	CGerror lastError = cgGetError();
	if(lastError) {
		const char *listing = cgGetLastListing(context);
		printf("%s\n", cgGetErrorString(lastError));
		printf("%s\n", listing);
		exit(-1);
	}
}

void initFrameBuffer()
{
	glewInit();

	GLuint shadowBufferID;

	glGenFramebuffersEXT(1,&bufferID);
	glGenFramebuffersEXT(1,&shadowBufferID);

	DistributeBuffer.SetBufferID(bufferID);
	DistributeBuffer.SetUpFBO(TEX,windowWidth,windowHeight);
	ShadowBuffer.SetBufferID(bufferID);
	ShadowBuffer.SetUpFBO(TEX,diffuseWidth*2,diffuseHeight*2);
	//ShadowBuffer.SetUpFBO(DEP,diffuseWidth*2,diffuseHeight*2,1,GL_DEPTH_COMPONENT32,GL_DEPTH_COMPONENT,GL_INT);
	//ShadowBuffer.SetUpFBO(DEP,windowWidth,windowHeight,GL_DEPTH_COMPONENT32,GL_DEPTH_COMPONENT,GL_INT);
	DiffuseBuffer.SetBufferID(bufferID);
	DiffuseBuffer.SetUpFBO(TEX,diffuseWidth,diffuseHeight);
	SpecularBuffer.SetBufferID(bufferID);
	SpecularBuffer.SetUpFBO(TEX,diffuseWidth,diffuseHeight);
	World2UVBuffer.SetBufferID(bufferID);
	World2UVBuffer.SetUpFBO(TEX,diffuseWidth,diffuseHeight);
	StretchUVBuffer.SetBufferID(bufferID);
	StretchUVBuffer.SetUpFBO(TEX,diffuseWidth,diffuseHeight);
	InterBuffer.SetBufferID(bufferID);
	InterBuffer.SetUpFBO(TEX,diffuseWidth,diffuseHeight);
	for (int i=0;i<BLURSTEP;i++)
	{
		GaussianBuffer[i].SetBufferID(bufferID);
		GaussianBuffer[i].SetUpFBO(TEX,diffuseWidth,diffuseHeight);
	}
}

void loadTexture()
{
	texture=new int[8];

	TextureHandler diffAlbedoHandler;
	diffAlbedoHandler.Load("diff.bmp");
	texture[0]=diffAlbedoHandler.ogl_id;
	diffuseWidth=diffAlbedoHandler.img_width;
	diffuseHeight=diffAlbedoHandler.img_height;

	TextureHandler specAlbedoHandler;
	specAlbedoHandler.Load("spec.bmp");
	texture[1]=specAlbedoHandler.ogl_id;
	

	/*TextureHandler chanelRHandler;
	chanelRHandler.Load("diff_normal_r.bmp");
	texture[1]=chanelRHandler.ogl_id;

	TextureHandler chanelGHandler;
	chanelGHandler.Load("diff_normal_g.bmp");
	texture[3]=chanelGHandler.ogl_id;

	TextureHandler chanelBHandler;
	chanelBHandler.Load("diff_normal_b.bmp");
	texture[2]=chanelBHandler.ogl_id;*/

	TextureHandler chanelSHandler;
	chanelSHandler.Load("spec_normal.bmp");
	texture[4]=chanelSHandler.ogl_id;

	diffAlbedoID=texture[0];
	specAlbedoID=texture[1];
	/*chanelR=texture[1];
	chanelB=texture[2];
	chanelG=texture[3];*/
	chanelS=texture[4];
}

void iniShader()
{
	fDistribute.m_parameters.clear();

	vShadow.m_parameters.clear();
	vShadow.AddParameter("Proj",CG_GL_ARBITRARY_MTX,LightProjectMatrix);
	vShadow.AddParameter("MV",CG_GL_ARBITRARY_MTX,LightMVMatrix);

	fShadow.m_parameters.clear();

	vWorld2UV.m_parameters.clear();

	fWorld2UV.m_parameters.clear();

	vStretchUV.m_parameters.clear();

	fStretchUV.m_parameters.clear();
	fStretchUV.AddParameter("worldCoord",CG_GL_TEXTURE_2D,&(World2UVBuffer.framebuffer.texID[0]));

	vDiffuse.m_parameters.clear();

	fDiffuse.m_parameters.clear();
	fDiffuse.AddParameter("albedo",CG_GL_TEXTURE_2D,&diffAlbedoID);
	/*fDiffuse.AddParameter("chanelR",CG_GL_TEXTURE_2D,&chanelR);
	fDiffuse.AddParameter("chanelG",CG_GL_TEXTURE_2D,&chanelG);
	fDiffuse.AddParameter("chanelB",CG_GL_TEXTURE_2D,&chanelB);*/
	fDiffuse.AddParameter("MInverse",CG_GL_ARBITRARY_MTX,MInvMatrix);
	fDiffuse.AddParameter("light",CG_GL_VECTOR_4D,light_position);
	fDiffuse.AddParameter("eye",CG_GL_VECTOR_4D,eye_position);
	fDiffuse.AddParameter("Kd",CG_GL_VECTOR_3D,Kd);
	fDiffuse.AddParameter("LMV",CG_GL_ARBITRARY_MTX,LightMVMatrix);
	fDiffuse.AddParameter("LProj",CG_GL_ARBITRARY_MTX,LightProjectMatrix);
	fDiffuse.AddParameter("step",CG_GL_VECTOR_2D,Step);
	fDiffuse.AddParameter("shadowMap",CG_GL_TEXTURE_2D,&(ShadowBuffer.framebuffer.texID[0]));

	vSpecular.m_parameters.clear();

	fSpecular.m_parameters.clear();
	fSpecular.AddParameter("albedo",CG_GL_TEXTURE_2D,&specAlbedoID);
	fSpecular.AddParameter("chanelS",CG_GL_TEXTURE_2D,&chanelS);
	fSpecular.AddParameter("beckmannTex",CG_GL_TEXTURE_2D,&(DistributeBuffer.framebuffer.texID[0]));
	fSpecular.AddParameter("MInverse",CG_GL_ARBITRARY_MTX,MInvMatrix);
	fSpecular.AddParameter("light",CG_GL_VECTOR_4D,light_position);
	fSpecular.AddParameter("eye",CG_GL_VECTOR_4D,eye_position);
	fSpecular.AddParameter("Kshine",CG_GL_VECTOR_1D,&Kshine);
	fSpecular.AddParameter("modelID",CG_GL_VECTOR_1D,&brdfID);
	fSpecular.AddParameter("m",CG_GL_VECTOR_1D,&KmC);
	fSpecular.AddParameter("fresnel",CG_GL_VECTOR_1D,&KfC);
	fSpecular.AddParameter("power",CG_GL_VECTOR_1D,&KsC);
	fSpecular.AddParameter("rough",CG_GL_VECTOR_1D,&KrC);

	vRender.m_parameters.clear();
	vRender.AddParameter("Proj",CG_GL_ARBITRARY_MTX,ProjectMatrix);
	vRender.AddParameter("MV",CG_GL_ARBITRARY_MTX,MVMatrix);

	fRender.m_parameters.clear();
	fRender.AddParameter("chanelD",CG_GL_TEXTURE_2D,&(DiffuseBuffer.framebuffer.texID[0]));
	fRender.AddParameter("chanelS",CG_GL_TEXTURE_2D,&(SpecularBuffer.framebuffer.texID[0]));
	fRender.AddParameter("shadowMap",CG_GL_TEXTURE_2D,&(ShadowBuffer.framebuffer.texID[0]));
	fRender.AddParameter("LProj",CG_GL_ARBITRARY_MTX,LightProjectMatrix);
	fRender.AddParameter("LMV",CG_GL_ARBITRARY_MTX,LightMVMatrix);
	fRender.AddParameter("step",CG_GL_VECTOR_2D,Step);

	vGaussianU.m_parameters.clear();

	fGaussianU.m_parameters.clear();
	fGaussianU.AddParameter("irradiance",CG_GL_TEXTURE_2D,&gaussianIrradiance);
	fGaussianU.AddParameter("position",CG_GL_TEXTURE_2D,&gaussianStretch);
	fGaussianU.AddParameter("width",CG_GL_VECTOR_1D,&gaussianWidth);

	vGaussianV.m_parameters.clear();

	fGaussianV.m_parameters.clear();
	fGaussianV.AddParameter("irradiance",CG_GL_TEXTURE_2D,&gaussianIrradiance);
	fGaussianV.AddParameter("position",CG_GL_TEXTURE_2D,&gaussianStretch);
	fGaussianV.AddParameter("width",CG_GL_VECTOR_1D,&gaussianWidth);
}

void loadShader()
{
	fDistribute.m_context=context;
	fDistribute.Load("fDistribute.cg",CG_GL_FRAGMENT);

	vShadow.m_context=context;
	vShadow.Load("vShadow.cg",CG_GL_VERTEX);

	fShadow.m_context=context;
	fShadow.Load("fShadow.cg",CG_GL_FRAGMENT);

	vDiffuse.m_context=context;
	vDiffuse.Load("vDiffuse.cg",CG_GL_VERTEX);

	fDiffuse.m_context=context;
	fDiffuse.Load("fDiffuse.cg",CG_GL_FRAGMENT);

	vSpecular.m_context=context;
	vSpecular.Load("vSpecular.cg",CG_GL_VERTEX);

	fSpecular.m_context=context;
	fSpecular.Load("fSpecular.cg",CG_GL_FRAGMENT);

	vRender.m_context=context;
	vRender.Load("vRender.cg",CG_GL_VERTEX);

	fRender.m_context=context;
	fRender.Load("fRender.cg",CG_GL_FRAGMENT);

	vWorld2UV.m_context=context;
	vWorld2UV.Load("vWorld2UV.cg",CG_GL_VERTEX);

	fWorld2UV.m_context=context;
	fWorld2UV.Load("fWorld2UV.cg",CG_GL_FRAGMENT);

	vStretchUV.m_context=context;
	vStretchUV.Load("vStretchUV.cg",CG_GL_VERTEX);

	fStretchUV.m_context=context;
	fStretchUV.Load("fStretchUV.cg",CG_GL_FRAGMENT);

	vGaussianU.m_context=context;
	vGaussianU.Load("vGaussianU.cg",CG_GL_VERTEX);

	fGaussianU.m_context=context;
	fGaussianU.Load("fGaussianU.cg",CG_GL_FRAGMENT);

	vGaussianV.m_context=context;
	vGaussianV.Load("vGaussianV.cg",CG_GL_VERTEX);

	fGaussianV.m_context=context;
	fGaussianV.Load("fGaussianV.cg",CG_GL_FRAGMENT);
}

void initCg()
{
	cgSetErrorCallback(cgErrorCallback);
	context=cgCreateContext();
}

void init()
{
	glLightfv(GL_LIGHT0, GL_POSITION, light_position);
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	glDepthFunc(GL_LESS);
	glEnable(GL_DEPTH_TEST);

	Step[0]=1.0/windowWidth;
	Step[1]=1.0/windowHeight;

}
void timer(int p)
{
	glutPostRedisplay();
	glutTimerFunc(20, timer, 0);
}

void updateCgParam()
{
	for (int i=0;i<3;i++)
	{
		Kd[i]=(float)KdC[i]/10.0;
	}
	Kshine=(float)KshineC;
}

void updateMatrix()
{

	float length=0;

	for (int i=0;i<3;i++)
	{
		light_position[i]=0;
		for (int j=0;j<3;j++)
		{
			light_position[i]+=lig_rot[j*4+i];
		}
		length+=light_position[i]*light_position[i];
	}	

	length=sqrt(length);

	for (int i=0;i<3;i++)
	{
		light_position[i]/=length;
		light_position[i]*=light_distance;
	}

	glViewport(0, 0, (GLsizei) diffuseWidth, (GLsizei) diffuseHeight);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0.0, diffuseWidth, 0.0, diffuseHeight);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(eye_position[0],eye_position[1],eye_position[2],0,0,0 ,0,1,0);
	glMultMatrixf(obj_rot);

	glGetFloatv(GL_PROJECTION_MATRIX,ProjectMatrix);
	glGetFloatv(GL_MODELVIEW_MATRIX,MVMatrix);	
	transposeMatrix(MTranMatrix,obj_rot);
	float invTemp[16];
	invertMatrix(invTemp,MTranMatrix);
	transposeMatrix(MInvMatrix,invTemp);
	//invertMatrix(MInvMatrix,obj_rot);
}

void drawModel()
{
	glCallList(displayID[0]);
}

void display()
{	

	printf("%d",brdfID);

	updateCgParam();

	// Beckmann Map Generation Pass

	DistributeBuffer.FBOActivate();

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0.0, windowWidth, 0.0, windowHeight);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glViewport(0, 0, windowWidth, windowHeight);

	glPolygonMode(GL_FRONT,GL_FILL);

	fDistribute.bind();

	glBegin(GL_QUADS);
	glTexCoord2f(0.0, 0.0); 
	glVertex2f(0.0, 0.0);
	glTexCoord2f(1.0, 0.0); 
	glVertex2f(windowWidth, 0.0);
	glTexCoord2f(1.0, 1.0); 
	glVertex2f(windowWidth, windowHeight);
	glTexCoord2f(0.0, 1.0); 
	glVertex2f(0.0, windowHeight);
	glEnd();

	fDistribute.release();

	DistributeBuffer.FBODeactivate();

	// Shadow Pass

	/*ShadowBuffer.FBOActivate();

	updateMatrix();

	glClearColor(0,0,0,0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glViewport(0, 0, diffuseWidth*2, diffuseHeight*2);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0f,(GLfloat) diffuseWidth / (GLfloat)diffuseHeight , 0.5f, -1000.0f);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	

	gluLookAt(-light_position[0],-light_position[1],-light_position[2],0,0,0 ,0,1,0);
	glMultMatrixf(obj_rot);

	glGetFloatv(GL_PROJECTION_MATRIX,LightProjectMatrix);
	glGetFloatv(GL_MODELVIEW_MATRIX,LightMVMatrix);	

	vShadow.bind();
	fShadow.bind();

	drawModel();

	vShadow.release();
	fShadow.release();

	ShadowBuffer.FBODeactivate();

	// World2UV Pass

	World2UVBuffer.FBOActivate();

	updateMatrix();

	vWorld2UV.bind();
	fWorld2UV.bind();

	drawModel();

	vWorld2UV.release();
	fWorld2UV.release();

	World2UVBuffer.FBODeactivate();

	// StretchUV Pass

	StretchUVBuffer.FBOActivate();

	updateMatrix();

	vStretchUV.bind();
	fStretchUV.bind();

	drawModel();

	vStretchUV.release();
	fStretchUV.release();

	StretchUVBuffer.FBODeactivate();

	// Gaussian Blur Pass

	float gVariance[6] = {0, 0.0484, 0.187, 0.567, 1.99, 7.41};
	float gWidth[6];

	gWidth[0] = 0;
	for(int i=1; i<6; i++)
	{
		float v = gVariance[i] - gVariance[i-1];
		gWidth[i] = sqrtf(v);
	}

	for(int i=0; i<6; i++){

		InterBuffer.FBOActivate();
		
		updateMatrix();
		gaussianStretch = StretchUVBuffer.framebuffer.texID[0];

		if(i==0)
			gaussianIrradiance = diffAlbedoID;
		else
			gaussianIrradiance = GaussianBuffer[i-1].framebuffer.texID[0];

		gaussianWidth = gWidth[i];

		vGaussianU.bind();
		fGaussianU.bind();
		
		drawModel();

		vGaussianU.release();
		fGaussianU.release();	

		InterBuffer.FBODeactivate();

		GaussianBuffer[i].FBOActivate();
		
		updateMatrix();
		gaussianStretch = StretchUVBuffer.framebuffer.texID[0];
		gaussianIrradiance = InterBuffer.framebuffer.texID[0];
		gaussianWidth = gWidth[i];

		vGaussianV.bind();
		fGaussianV.bind();
		
		drawModel();

		vGaussianV.release();
		fGaussianV.release();	

		GaussianBuffer[i].FBODeactivate();

	}

	// Diffuse Pass

	DiffuseBuffer.FBOActivate();

	updateMatrix();

	vDiffuse.bind();
	fDiffuse.bind();

	drawModel();

	fDiffuse.release();
	vDiffuse.release();

	DiffuseBuffer.FBODeactivate();*/

	// Specular Pass                                                        

	SpecularBuffer.FBOActivate();

	updateMatrix();

	vSpecular.bind();
	fSpecular.bind();

	drawModel();

	fSpecular.release();
	vSpecular.release();

	SpecularBuffer.FBODeactivate();

	// Final Combination  

#if 1

	glClearColor(0,0,0,1);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0f,(GLfloat) windowWidth / (GLfloat)windowHeight , 0.5f, -1000.0f);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glViewport(0, 0, windowWidth, windowHeight);

	gluLookAt(eye_position[0],eye_position[1],eye_position[2],0,0,0 ,0,1,0);
	glMultMatrixf(obj_rot);

	glGetFloatv(GL_PROJECTION_MATRIX,ProjectMatrix);
	glGetFloatv(GL_MODELVIEW_MATRIX,MVMatrix);	

	//vRender.bind();
	//fRender.bind();

	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D,SpecularBuffer.framebuffer.texID[0]);

	glCallList(displayID[0]);

	glDisable(GL_TEXTURE_2D);

	//fRender.release();
	//vRender.release();

#else

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0.0, windowWidth, 0.0, windowHeight);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glViewport(0, 0, windowWidth, windowHeight);

	glPolygonMode(GL_FRONT,GL_FILL);

	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D,DistributeBuffer.framebuffer.texID[0]);

	glBegin(GL_QUADS);
	glTexCoord2f(0.0, 0.0); 
	glVertex2f(0.0, 0.0);
	glTexCoord2f(1.0, 0.0); 
	glVertex2f(windowWidth, 0.0);
	glTexCoord2f(1.0, 1.0); 
	glVertex2f(windowWidth, windowHeight);
	glTexCoord2f(0.0, 1.0); 
	glVertex2f(0.0, windowHeight);
	glEnd();

	glDisable(GL_TEXTURE_2D);

#endif	

	glutSwapBuffers(); 

}

void reshape(int w, int h)
{
	glViewport(0, 0, (GLsizei) w, (GLsizei) h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0f,(GLfloat) w / (GLfloat)h , 0.5f, -1000.0f);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void InitModel()
{
	displayID = (int*)malloc(sizeof(int));

	
	mesh.LoadOBJascii("lowres.obj");

	displayID[0] = glGenLists(1);
	glNewList(displayID[0], GL_COMPILE);
	glBegin(GL_TRIANGLES);
	for(int j=0; j<mesh.numTris; j++){
		int indexV1 = mesh.tris[j].v1;
		int indexV2 = mesh.tris[j].v2;
		int indexV3 = mesh.tris[j].v3;
		int indexUV1 = mesh.tris[j].uv1;
		int indexUV2 = mesh.tris[j].uv2;
		int indexUV3 = mesh.tris[j].uv3;
		glTexCoord2f(mesh.uvs[indexUV1].u, mesh.uvs[indexUV1].v); 
		glNormal3f(mesh.normal[indexV1].x, mesh.normal[indexV1].y, mesh.normal[indexV1].z);
		glColor3f(mesh.tangent[indexV1].x, mesh.tangent[indexV1].y, mesh.tangent[indexV1].z);
		glVertex3f(mesh.verts[indexV1].x, mesh.verts[indexV1].y, mesh.verts[indexV1].z);

		glTexCoord2f(mesh.uvs[indexUV2].u, mesh.uvs[indexUV2].v); 
		glNormal3f(mesh.normal[indexV2].x, mesh.normal[indexV2].y, mesh.normal[indexV2].z);
		glColor3f(mesh.tangent[indexV2].x, mesh.tangent[indexV2].y, mesh.tangent[indexV2].z);
		glVertex3f(mesh.verts[indexV2].x, mesh.verts[indexV2].y, mesh.verts[indexV2].z);

		glTexCoord2f(mesh.uvs[indexUV3].u, mesh.uvs[indexUV3].v); 
		glNormal3f(mesh.normal[indexV3].x, mesh.normal[indexV3].y, mesh.normal[indexV3].z);
		glColor3f(mesh.tangent[indexV3].x, mesh.tangent[indexV3].y, mesh.tangent[indexV3].z);
		glVertex3f(mesh.verts[indexV3].x, mesh.verts[indexV3].y, mesh.verts[indexV3].z);
	}
	glEnd();
	glEndList();
}

void Keyboard(unsigned char Key, int x, int y)
{
	switch(Key)
	{
	case 'a':
		if (gaussianDisplay>0)
		{
			gaussianDisplay--;
		}	
		break;

	case 's':
		if (gaussianDisplay<BLURSTEP-1)
		{
			gaussianDisplay++;
		}
		break;
	}

	printf("$$$$%d\n",gaussianDisplay);

	glutPostRedisplay();
}

void updateBRDFModel(int arg)
{
	switch (brdfID)
	{
	case 0:
		phongPanel->enable();
		torrancePanel->disable();
		kelemenPanel->disable();
		break;

	case 1:
		torrancePanel->enable();
		phongPanel->disable();
		kelemenPanel->disable();
		break;

	case 2:
		kelemenPanel->enable();
		phongPanel->disable();
		torrancePanel->disable();
		break;

	default:
		break;
	}

}

int main(int argc, char *argv[])
{

	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowPosition(0, 0);
	glutInitWindowSize(windowWidth, windowHeight);
	GLuint win=glutCreateWindow("Hybrid Normal");
	init();
	initCg();
	InitModel();
	loadTexture();
	initFrameBuffer();
	loadShader();
	iniShader();
	glutTimerFunc(20,timer,0);
	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
	glutKeyboardFunc(Keyboard);

	glui=GLUI_Master.create_glui("Control");

	GLUI_Rollout *Rotation=glui->add_rollout("Rotation");
	GLUI_Rotation *ro=glui->add_rotation_to_panel(Rotation,"World Rotation",(float*)obj_rot);
	ro->reset();
	GLUI_Rotation *rl=glui->add_rotation_to_panel(Rotation,"Light Rotation",(float*)lig_rot);
	rl->reset();

	GLUI_Rollout *Translation=glui->add_rollout("Translation");
	GLUI_Translation *tc=glui->add_translation_to_panel(Translation,"Camera Translation",GLUI_TRANSLATION_Z,&(eye_position[2]));
	tc->set_speed(0.5);
	tc->set_z(eye_position[2]);
	GLUI_Translation *tl=glui->add_translation_to_panel(Translation,"Light Translation",GLUI_TRANSLATION_Z,&(light_distance));
	tl->set_speed(0.5);
	tl->set_z(light_distance);

	GLUI_Rollout *DiffuseLightControl=glui->add_rollout("Diffuse Lighting");
	GLUI_Spinner *kdr=glui->add_spinner_to_panel(DiffuseLightControl,"Diffuse R Kd",GLUI_SPINNER_INT,&(KdC[0]));
	kdr->set_int_limits(0,10);
	GLUI_Spinner *kdg=glui->add_spinner_to_panel(DiffuseLightControl,"Diffuse G Kd",GLUI_SPINNER_INT,&(KdC[1]));
	kdg->set_int_limits(0,10);
	GLUI_Spinner *kdb=glui->add_spinner_to_panel(DiffuseLightControl,"Diffuse B Kd",GLUI_SPINNER_INT,&(KdC[2]));
	kdb->set_int_limits(0,10);

	GLUI_Rollout *SpecularLightControl=glui->add_rollout("Specular Lighting");
	GLUI_RadioGroup *brdfModel=glui->add_radiogroup_to_panel(SpecularLightControl,&brdfID,23,updateBRDFModel);
	GLUI_RadioButton *phong=glui->add_radiobutton_to_group(brdfModel,"Phong");
	GLUI_RadioButton *torrance=glui->add_radiobutton_to_group(brdfModel,"Torrance");
	GLUI_RadioButton *kelemen=glui->add_radiobutton_to_group(brdfModel,"Kelemen");

	phongPanel=glui->add_panel_to_panel(SpecularLightControl,"Phong Model");
	GLUI_Spinner *ksh=glui->add_spinner_to_panel(phongPanel,"Specular Shine",GLUI_SPINNER_INT,&KshineC);
	ksh->set_int_limits(0,100);

	torrancePanel=glui->add_panel_to_panel(SpecularLightControl,"Torrance Model");
	GLUI_Spinner *m_t=glui->add_spinner_to_panel(torrancePanel,"M",GLUI_SPINNER_FLOAT,&KmC);
	m_t->set_float_limits(0,10);
	GLUI_Spinner *fresnel_t=glui->add_spinner_to_panel(torrancePanel,"Fresnel",GLUI_SPINNER_FLOAT,&KfC);
	fresnel_t->set_float_limits(0,10);

	kelemenPanel=glui->add_panel_to_panel(SpecularLightControl,"Kelemen Model");
	GLUI_Spinner *ksh_k=glui->add_spinner_to_panel(kelemenPanel,"Specular Shine",GLUI_SPINNER_INT,&KsC);
	ksh_k->set_int_limits(0,100);
	GLUI_Spinner *rough_k=glui->add_spinner_to_panel(kelemenPanel,"Rough",GLUI_SPINNER_FLOAT,&KrC);
	rough_k->set_float_limits(0,10);

	torrancePanel->disable();
	kelemenPanel->disable();

	glui->set_main_gfx_window(win);

	glutMainLoop();
	return 0;
}